#include <stdio.h>  
#include <string.h>  
#include <sstream>
#include <fstream>
#include "MQuoteHandler.h"
#include "utils/utils.h"
#include "utils/json11.hpp"
#include "utils/MyHash.h"
#include "utils/redis_handler.h"
using namespace json11;

#define CONFIG_FILE "./config.json"
Config g_config;
Futures_Internal_Book g_fbook = { 0 };
MyHash<Quote> g_quote_hash;
char QUOTEDATA[4096] = { 0 };

RedisHandler *g_redis_handler = NULL;
RedisList *g_redis_contract = NULL;
RedisList *g_redis_multi_quote = NULL;

void read_config_file(std::string& content)
{
	std::ifstream fin(CONFIG_FILE);
	std::stringstream buffer;
	buffer << fin.rdbuf();
	content = buffer.str();
	fin.close();
}

void read_json_config() {
	std::string json_config;
	read_config_file(json_config);
	std::string err_msg;
	Json l_json = json11::Json::parse(json_config, err_msg, JsonParse::COMMENTS);
	if (err_msg.length() > 0) {
		printf("Json parse fail, please check your setting! %s\n", err_msg.c_str());
		return;
	}
	strcpy(g_config.MBL_IP, l_json["MBL_IP"].string_value().c_str());
	g_config.MBL_PORT = l_json["MBL_PORT"].int_value();
	strcpy(g_config.MBL_USERNAME, l_json["MBL_USERNAME"].string_value().c_str());
	strcpy(g_config.MBL_PASSWORD, l_json["MBL_PASSWORD"].string_value().c_str());

	strcpy(g_config.REDIS_HOST, l_json["REDIS_IP"].string_value().c_str());
	g_config.REDIS_PORT = l_json["REDIS_PORT"].int_value();
	strcpy(g_config.REDIS_CONTRACT, l_json["REDIS_CONTRACT"].string_value().c_str());
	strcpy(g_config.REDIS_MULTI_QUOTE, l_json["REDIS_MULTI_QUOTE"].string_value().c_str());
	strcpy(g_config.REDIS_MULTI_QUOTE_CACHE, l_json["REDIS_MULTI_QUOTE_CACHE"].string_value().c_str());
}

MQuoteHandler::MQuoteHandler(MBLApi *pMBLApi) {
	m_pMBLApi = pMBLApi;
	read_json_config();

	g_redis_handler = new RedisHandler(g_config.REDIS_HOST, g_config.REDIS_PORT);
	g_redis_contract = new RedisList(g_redis_handler, g_config.REDIS_CONTRACT);
	g_redis_multi_quote = new RedisList(g_redis_handler, g_config.REDIS_MULTI_QUOTE_CACHE);

	m_pMBLApi->MBLRegisterSpi(this);
	m_pMBLApi->MBLSetIPInfo(g_config.MBL_IP, g_config.MBL_PORT);
	m_pMBLApi->MBLInit();
}

MQuoteHandler::~MQuoteHandler()
{
	delete g_redis_handler;
	delete g_redis_contract;
	delete g_redis_multi_quote;
}

void MQuoteHandler::OnMBLConnected() {
	printf("Entering OnMBLConnected...\n");
	MBLUserData strData;
	strcpy(strData.username, g_config.MBL_USERNAME);
	strcpy(strData.password, g_config.MBL_PASSWORD);
	m_pMBLApi->MBLReqUserLogin(&strData);
}

void MQuoteHandler::OnMBLRspUserLogin(MBLErrorInfo ErrorInfo) {
	if (ErrorInfo == MBL_NO_ERROR) {
		printf("MBLLogin Success!\n");
		printf("Wait for contract info from redis...\n");
		char* contract_list = g_redis_contract->blpop();
		m_pMBLApi->MBLReqSubcribe(contract_list);
		printf("ReqMBLSubcribe: %s\n", contract_list);
	}
	else {
		printf("ErrorInfo = %d\n", ErrorInfo);
	}
}

void MQuoteHandler::OnMBLRspSubcribe(MBLErrorInfo ErrorInfo) {
	if (ErrorInfo == MBL_NO_ERROR) {
		printf("MBLSubcribe Success!\n");
		m_pMBLApi->SetMBLDataPushingFlag(true);
	}
}

bool format_future_quote(Quote &quote, char* symbol) {
	g_fbook.int_time = quote.int_time;
	strcpy(g_fbook.symbol, symbol);

	for(int i = 0; i < 5; i++) {
		g_fbook.bp_array[i] = quote.price[0][i];
		g_fbook.bv_array[i] = quote.size[0][i];
		g_fbook.ap_array[i] = quote.price[1][i];
		g_fbook.av_array[i] = quote.size[1][i];
	}
	return true;
}

int index = 0;
int cur_direction = 0;
long long time_start = 0, time_end = 0;

void MQuoteHandler::OnMBLRspMarketData(MBLData *pMBLMarketData) {
	time_end = get_time_stamp();

	char* symbol = pMBLMarketData->instrumentID;
	Quote &quote = g_quote_hash[symbol];
	quote.int_time = convert_time(pMBLMarketData->timestamp);
	int direction = pMBLMarketData->direction - '0';
	int time_diff = get_us_time_diff(time_start, time_end);
	if(time_diff > 100 || cur_direction != direction) {
		// means restart buy/sell
		index = 0;
		memset(quote.price[direction], 0, 10 * sizeof(double));
		memset(quote.size[direction], 0, 10 * sizeof(int));
		cur_direction = direction;
	}
	
	quote.price[direction][index] = pMBLMarketData->price;
	quote.size[direction][index] = pMBLMarketData->volume;
	index++;
	
	printf("timestamp: %d\tinstrumentID:%s\tdirection:%d\tprice:%f\tvolume:%d\tdataSource:%d\n", quote.int_time, symbol, direction, pMBLMarketData->price,
		pMBLMarketData->volume, pMBLMarketData->dataSource);

	if (index == 10 && direction == 1) {
		sprintf(QUOTEDATA, "%d %s \n%f %f %f %f %f %f %f %f %f %f\n%d %d %d %d %d %d %d %d %d %d\n%f %f %f %f %f %f %f %f %f %f\n%d %d %d %d %d %d %d %d %d %d",
			quote.int_time, symbol,
			quote.price[0][0], quote.price[0][1], quote.price[0][2], quote.price[0][3], quote.price[0][4], quote.price[0][5], quote.price[0][6], quote.price[0][7], quote.price[0][8], quote.price[0][9],
			quote.size[0][0], quote.size[0][1], quote.size[0][2], quote.size[0][3], quote.size[0][4], quote.size[0][5], quote.size[0][6], quote.size[0][7], quote.size[0][8], quote.size[0][9],
			quote.price[1][0], quote.price[1][1], quote.price[1][2], quote.price[1][3], quote.price[1][4], quote.price[1][5], quote.price[1][6], quote.price[1][7], quote.price[1][8], quote.price[1][9],
			quote.size[1][0], quote.size[1][1], quote.size[1][2], quote.size[1][3], quote.size[1][4], quote.size[1][5], quote.size[1][6], quote.size[1][7], quote.size[1][8], quote.size[1][9]);
		if(format_future_quote(quote, symbol)) {
			printf("push multi quote to redis\n");
			g_redis_multi_quote->rpush_binary((char*)&g_fbook, sizeof(Futures_Internal_Book));
		}
		printf("\n********************\n%s\n********************\n\n", QUOTEDATA);
	}

	time_start = get_time_stamp();
}